from django.http import Http404, HttpResponseRedirect, HttpResponse
from django.template import RequestContext
from django.contrib.auth import logout, login, authenticate
from django.contrib.auth.models import User
from django.contrib.auth.decorators import login_required
from django.contrib.auth.forms import PasswordChangeForm
from django.contrib.gis.geos import fromstr
from django.contrib.gis.measure import D # D is a short for Distance
from django.db.models import Q
from django.shortcuts import render_to_response, get_object_or_404
from django.utils import simplejson
from reviews.models import Dish, Place, DishImage
from reviews.forms import ReviewForm, RegistrationForm, UploadDishPhotoForm, SearchForm, EditTagsForm, QuickReviewForm, AddDishForm
from reviews.serialization_helpers import *
from sorting.models import SortDelta

from tagging.models import Tag
from tagging.utils import parse_tags, edit_string_for_tags
from datetime import datetime

@login_required
def submit_ranking(request):
    try:
        if request.is_ajax():
            # print 'Raw Data: "%s"' % request.raw_post_data
            json_data = simplejson.loads(request.raw_post_data)
            myTag = Tag.objects.get(id=json_data['tagId'])
            newRanking, created = Ranking.objects.get_or_create(tag=myTag, user=request.user)
            # print 'here'
            idx = 1
            for dishId in json_data['ranking']:
                dish = Dish.objects.get(id=dishId)
                rank, created = Rank.objects.get_or_create(dish=dish, ranking=newRanking)
                if json_data['text'][idx-1]:
                    print json_data['text'][idx-1]
                    rank.comment = json_data['text'][idx-1].strip()
                else:
                    rank.comment = ""
                rank.rank = idx
                print rank.comment
                rank.save()
                # print 'after save'
                idx = idx + 1

        return HttpResponse('Success');
    except:
       return HttpResponse('Fail');
    
def register_page(request):
    if request.method == 'POST':
        form = RegistrationForm(request.POST)
        if form.is_valid():
            cd = form.cleaned_data
            user = User.objects.create_user(
                username = cd['username'].lower(),
                password = cd['password1'],
                email = cd['email']
            )
            # automagically log user in
            user = authenticate(username = cd['username'].lower(), password = cd['password1'])
            login(request, user)
            return HttpResponseRedirect('/')
    else:
        form = RegistrationForm()
    variables = RequestContext(request, { 'form': form })
    return render_to_response('registration/register.html', variables)

def log_user_out(request):
    logout(request)
    return HttpResponseRedirect('/')

def user_page(request, user_name):
    try:
        user = User.objects.get(username=user_name)
    except User.DoesNotExist:
        raise Http404('Requested user not found.')
    variables = RequestContext(request, {
        'user_public' : user,
        'show_edit' : user_name == request.user.username,
    })
    return render_to_response('reviews/user_page.html', variables)

def home(request):
    dishes = Dish.objects.order_by('-created_date')
    id_dish = [(d.id, d) for d in dishes]

    variables = RequestContext(request, {
        'id_dish_coll': id_dish,
        'dishes_json': serialize_dishes(dishes, request.user),
    })
    

    # tags = Tag.objects.all().order_by('name')

    # td = []
    # for tag in tags:
        # td.append(( tag, 
            # Dish.objects.filter(rank__ranking__tag__id=tag.id).filter(rank__ranking__user__username="kokoomi").order_by('-rank') ))

    # dut = []
    # for tag, dishes in td:
        # tmp_dut = []
        # for dish in dishes:
            # print dish.last_sorted_user_id
            # # REMEMBER TO CHECK IF DISH HAS BEEN RANKED
            # tmp_dut.append(( dish, User.objects.get(id=dish.last_sorted_user_id), dish.last_sorted_date_time ))
        # dut.append(( tag, tmp_dut ))

    # # find recent diffs and display..
    
    # variables = RequestContext(request, {
        # 'td': dut,
    # })

    return render_to_response('reviews/main_page.html', variables)

def search(request):
    dishes = Dish.objects.all()
    if 'query' in request.GET:
        query = request.GET['query'].strip()
        if query:
            form = SearchForm({'query' : query}) 
            dishes = dishes.filter(name__icontains=query)

    if 'lat' in request.GET and 'lng' in request.GET:
        # filter dishes based on lat, lng
        lat = request.GET['lat'].strip()
        lng = request.GET['lng'].strip()
        if lat and lng:
            # need to populate form with search value like above
            pnt = fromstr('POINT(' + lat + ' ' + lng + ')', srid=4326)
			# filter dishes that are within D distance from pnt and attach a distance attribute
            dishes = dishes.filter(place__geometry__distance_lte=(pnt, D(mi=10))).distance(pnt, field_name='place__geometry')

    variables = RequestContext(request, {
        'dishes_json': serialize_dishes(dishes, request.user),
        'show_edit' : request.user.is_authenticated(),
        'isMapsView': 1
    })
    if request.GET.has_key('ajax'):
        return HttpResponse(variables['dishes_json'], mimetype='application/javascript')
        #return render_to_response('reviews/dish_list.html', variables)
    else:
        return render_to_response('reviews/search_page.html', variables)

# def tag(request, tag_id):
    # '''List all the dishes associated with the specified tag.'''
    # tag = get_object_or_404(Tag, id=tag_id)
    # related_tags = tag.all_related_tags()
    # return render_to_response('reviews/tag.html', RequestContext(request, {'tag' : tag, 'related_tags' : related_tags}))

@login_required
def submit_tags(request, dish_id):
    dish = get_object_or_404(Dish, id=dish_id)
    ajax = 'ajax' in request.GET
    initial_data = {}
    if request.method == 'POST':
        form = EditTagsForm(request.POST)
        if form.is_valid():
            cd = form.cleaned_data
			# parse tags and add to dish
            # what if users are stupid and tag dishes badly?
            tag_string = cd['tags']
            tag_list = parse_tags(tag_string)
            #tag_obj_list = []
            dish.tags.clear()
            for tag in tag_list:
                tag_obj, dummy = Tag.objects.get_or_create(name = tag)
                #tag_obj_list.append(tag_obj)
                if not tag_obj in dish.tags.all():
                    dish.tags.add(tag_obj)
            if ajax:
                variables = RequestContext(request, {
                    'dish': dish,
                    'show_edit': request.user.is_authenticated(),
                    })
                return render_to_response(
                    'reviews/tag_list.html', variables
                )
            
            return HttpResponseRedirect('/dish/' + str(dish.id))
        else:
            if ajax:
                return HttpResponse(u'failure')
    tags_string = edit_string_for_tags(dish.tags.all())
    initial_data['tags'] = tags_string
    initial_data['dish_id'] = dish_id
    form = EditTagsForm(
        initial = initial_data
    )
    if ajax:
        return render_to_response('reviews/edit_tags_form.html', {'form': form},
                                  context_instance=RequestContext(request))

    return render_to_response('reviews/submit_form_page.html', {'form': form},
                              context_instance=RequestContext(request))

def add_dish(request, place_id):
    f = AddDishForm(request.POST)
    if f.is_valid():
        new_dish = f.save(commit=False)
        new_dish.place = get_object_or_404(Place, id=place_id)
        new_dish.save()
        f.save_m2m()
        return HttpResponse(u'Success')
    return HttpResponse(u'Failure')

def dish_name_check(request, place_id):
    d = Dish.objects.filter(name__iexact=request.GET['name'].strip(), place__id=place_id)
    if d:
        return HttpResponse(u'invalid')
    return HttpResponse(u'valid')

def place(request, place_slug):

    dishes = Dish.objects.order_by('-created_date')
    id_dish = [(d.id, d) for d in dishes]
    
    place = get_object_or_404(Place, slug=place_slug)
    variables = RequestContext(request, {
        'id_dish_coll': id_dish,
        'place' : place,
        'add_dish_form' : AddDishForm(),
        'dishes_json': serialize_dishes(dishes, request.user),
    })
    return render_to_response('reviews/place.html', variables)


def tag(request, tag_name):
    tag = get_object_or_404(Tag, slug=tag_name)
    dishes = tag.dish_set.all()
    #reviews = Rank.objects.filter(~Q(comment = ""))
    #rankings = Ranking.objects.filter(tag__name__iexact=tag_name)
    
    variables = RequestContext(request, {
        'tag_id' : tag.id,
        'tag' : tag,
        'dishes' : dishes,
        'dishes_json': serialize_dishes(dishes, request.user),
        #'num_dishes': len(dishes),
        #'num_reviews': len(reviews),
        #'num_ranks': len(rankings),
        #'show_edit' : request.user.is_authenticated(),
        #'isMapsView': 1,
        #'shouldDisplayNames': 1
    })
    return render_to_response('reviews/tag.html', variables)

def dish(request, dish_id):
    '''List all the reviews for the given dish'''
    d = get_object_or_404(Dish, id=dish_id)

    variables = RequestContext(request, {
        'dish' : d,
    })
    return render_to_response('reviews/dish.html', variables)

def dish_page(request, dish_slug):
    '''List all the reviews for the given dish'''
    d = get_object_or_404(Dish, slug=dish_slug)

    variables = RequestContext(request, {
        'dish' : d,
    })
    return render_to_response('reviews/dish_page.html', variables)

@login_required
def add_photo(request, dish_id):
    if dish_id:
        dish = get_object_or_404(Dish, id=dish_id)
    if request.method == 'POST':
        form = UploadDishPhotoForm(request.POST, request.FILES)
        if form.is_valid():
            new_dish_image = form.save(commit=False)
            new_dish_image.dish = dish
            new_dish_image.user = request.user
            new_dish_image.save()
            return HttpResponseRedirect('/dish/' + str(dish.id))
    else:
        form = UploadDishPhotoForm()
    return render_to_response('reviews/upload.html', {'form': form}, context_instance=RequestContext(request))

@login_required
def submit_dish(request):
    dish_id = None
    if request.method == 'POST':
        form = ReviewForm(request.POST)
        if form.is_valid():
            cd = form.cleaned_data
            placename = cd['place']
            place, dummy = Place.objects.get_or_create(name = placename)
            dish, dummy = Dish.objects.get_or_create(name = cd['name'],
                                              place = place)
            dish_id = dish.id
            return submit_review(request, dish_id)
    else:
        initial_data = {'text': 'Write stuff here.'}
        form = ReviewForm(initial = initial_data)
        return render_to_response('reviews/submit_form_page.html', {'form': form},
                                  context_instance=RequestContext(request))

@login_required
def submit_tags(request, dish_id):
    dish = get_object_or_404(Dish, id=dish_id)
    ajax = 'ajax' in request.GET
    initial_data = {}
    if request.method == 'POST':
        form = EditTagsForm(request.POST)
        if form.is_valid():
            cd = form.cleaned_data
			# parse tags and add to dish
            # what if users are stupid and tag dishes badly?
            tag_string = cd['tags']
            tag_list = parse_tags(tag_string)
            #tag_obj_list = []
            dish.tags.clear()
            for tag in tag_list:
                tag_obj, dummy = Tag.objects.get_or_create(name = tag)
                #tag_obj_list.append(tag_obj)
                if not tag_obj in dish.tags.all():
                    dish.tags.add(tag_obj)
            if ajax:
                variables = RequestContext(request, {
                    'dish': dish,
                    'show_edit': request.user.is_authenticated(),
                    })
                return render_to_response(
                    'reviews/tag_list.html', variables
                )
            
            return HttpResponseRedirect('/dish/' + str(dish.id))
        else:
            if ajax:
                return HttpResponse(u'failure')
    tags_string = edit_string_for_tags(dish.tags.all())
    initial_data['tags'] = tags_string
    initial_data['dish_id'] = dish_id
    form = EditTagsForm(
        initial = initial_data
    )
    if ajax:
        return render_to_response('reviews/edit_tags_form.html', {'form': form},
                                  context_instance=RequestContext(request))

    return render_to_response('reviews/submit_form_page.html', {'form': form},
                              context_instance=RequestContext(request))

# @login_required
# def delete_review_or_image(request):
    # if 'review_id' in request.GET:
        # review_id = request.GET['review_id']
        # review = get_object_or_404(Review, id=review_id)
        # review.delete()
    # elif 'photo_id' in request.GET:
        # photo_id = request.GET['photo_id']
        # photo = get_object_or_404(DishImage, id=photo_id)
        # photo.delete()
    # return HttpResponseRedirect('/user/' + str(request.user.username))
# @login_required

# def submit_review(request, dish_id):
    # dish = get_object_or_404(Dish, id=dish_id)
    # initial_data = {}
    # if request.method == 'POST':
        # form = QuickReviewForm(request.POST)
        # if form.is_valid():
            # cd = form.cleaned_data
            # review = Review.objects.create(text = cd['text'],
                                           # dish = dish,
                                           # user = request.user)
            # dish.review_set.add(review)
            # return HttpResponse(serialize_dishes([dish], request.user), mimetype='application/javascript')
    # else:
        # initial_data['text'] = 'Write stuff here.'
    # form = QuickReviewForm(
        # initial = initial_data
    # )
    # return render_to_response('reviews/quick_review_template.html', {'form': form},
                              # context_instance=RequestContext(request))

# @login_required
# def submit_review(request, dish_id):
    # dish = get_object_or_404(Dish, id=dish_id)
    # initial_data = {}
    # if request.method == 'POST':
        # form = ReviewForm(request.POST)
        # if form.is_valid():
            # cd = form.cleaned_data
            # if 'review_id' in cd and cd['review_id']:
                # review_id = cd['review_id']
                # review = Review.objects.get(id = review_id)
                # review.text = cd['text']
                # review.rating = cd['rating']
            # else:
                # review = Review.objects.create(text = cd['text'],
                                           # dish = dish,
                                           # user = request.user,
                                           # rating = cd['rating'])
			# # parse tags and add to dish
            # # what if users are stupid and tag dishes badly?
            # tag_string = cd['tags']
            # tag_list = parse_tags(tag_string)
            # for tag in tag_list:
                # tag_obj, dummy = Tag.objects.get_or_create(name = tag)
                # tag_obj.review_set.add(review)
                # if not tag_obj in dish.tags.all():
                    # dish.tags.add(tag_obj)

            # dish.review_set.add(review)
            # return HttpResponseRedirect('/dish/' + str(dish.id))
    # elif 'review_id' in request.GET: # case for editing an existing review
        # review_id = request.GET['review_id']
        # try:
            # review = Review.objects.get(id = review_id)
            # tags_string = edit_string_for_tags(review.tags.all())
            # initial_data['tags'] = tags_string
            # initial_data['text'] = review.text
            # initial_data['rating'] = review.rating
            # initial_data['review_id'] = review.id
        # except (Review.DoesNotExist):
            # pass


    # else: # case for new review
        # initial_data['text'] = 'Write stuff here.'
    # initial_data['name'] = dish.name
    # initial_data['place'] = dish.place
 
    # form = ReviewForm(
        # initial = initial_data
    # )
    # return render_to_response('reviews/submit_form_page.html', {'form': form},
                              # context_instance=RequestContext(request))

# def add_dish(request):
    # #dish = get_object_or_404(Dish, id=dish_id)
    # if request.method == 'POST':
        # form = NewDishForm(request.POST)
        # if form.is_valid():
            # cd = form.cleaned_data
            # dish = Dish.objects.create(name = cd['name'],
                                       # place = cd['place'])
            # review.save()
            # return HttpResponseRedirect('/')
    # else:
        # form = ReviewForm(
            # initial = {'text': 'Write stuff here.'}
        # )
    # return render_to_response('reviews/review.html', {'form': form, 'dish': dish},
                              # context_instance=RequestContext(request))

# def add_review(request, dish_id):
    # dish = get_object_or_404(Dish, id=dish_id)
    # try:
        # review = Review.objects.create(text=str(request.POST['review_text']), dish=dish)
    # except (KeyError):
        # # Redisplay the review form.
        # return render_to_response('reviews/review.html', {
            # 'dish': dish,
            # 'error_message': "You didn't seleAdasdfasfct a choice.",
        # }, context_instance=RequestContext(request))
    # else:
        # review.save()
        # # Always return an HttpResponseRedirect after successfully dealing
        # # with POST data. This prevents data from being posted twice if a
        # # user hits the Back button.
        # return HttpResponseRedirect(reverse('reviews.views.dish', args=(dish.id,)))